using System;
using System.IO;

namespace MH.WsdlWorks.ProjectModel
{
    public static class Utilities
    {
        public static string GetUniqueFileName(string path)
        {
            FileNameInfo fileNameInfo = new FileNameInfo(path, false);
            return fileNameInfo.Path;
        }

        public static string GetUniqueFileName(string fileName, string parentFolderPath)
        {
            string fullFilePath = GetUniqueFileName(System.IO.Path.Combine(parentFolderPath, fileName));
            return System.IO.Path.GetFileName(fullFilePath);
        }

        public static string GetUniqueFolderName(string path)
        {
            FileNameInfo fileNameInfo = new FileNameInfo(path, true);
            return fileNameInfo.Path;
        }

        public static string GetUniqueFolderName(string folderName, string parentFolderPath)
        {
            string fullFolderPath = GetUniqueFolderName(System.IO.Path.Combine(parentFolderPath, folderName));
            return GetDirectoryNameFromPath(fullFolderPath);
        }

        public static string GetDirectoryNameFromPath(string path)
        {
            string[] pathArray = path.Split('\\');
            return pathArray[pathArray.GetUpperBound(0)];
        }

        static string GetDirectory(string path)
        {
            string newDirectory = System.IO.Path.GetDirectoryName(path);
            if (newDirectory.EndsWith("\\"))
            {
                newDirectory = newDirectory.Substring(0, newDirectory.Length - 2);
            }
            return newDirectory;
        }

        private struct FileNameInfo
        {
            string fileName;
            string fileNameWithoutNumber;
            string extension;
            string directory;

            int pos;
            long number;

            bool isDirectory;

            public FileNameInfo(string path, bool isDirectory)
            {
                if (string.IsNullOrEmpty(path))
                {
                    throw new ArgumentNullException("path");
                }
                if (!System.IO.Path.IsPathRooted(path))
                {
                    throw new InvalidDataException("path must be rooted");
                }

                this.isDirectory = isDirectory;

                // make sure that directories end with \
                if (this.isDirectory)
                {
                    if (!path.EndsWith("\\"))
                    {
                        path = path + "\\";
                    }
                }

                this.fileName = System.IO.Path.GetFileNameWithoutExtension(path);
                this.extension = System.IO.Path.GetExtension(path);
                this.directory = Utilities.GetDirectory(path);

                // if it's a directory, we just use the same procedure as a file, but pretend that
                // the leaf directory node is the filename.
                if (this.isDirectory)
                {
                    this.fileName = Utilities.GetDirectoryNameFromPath(this.directory);
                    this.directory = this.directory.Replace(this.fileName, string.Empty);
                }

                this.fileNameWithoutNumber = this.fileName;
                this.pos = 0;
                this.number = 0;

                if (this.Exists())
                {
                    CreateFileNameWithoutNumber();
                    CreateNewFileName();
                }
            }

            void CreateFileNameWithoutNumber()
            {
                while (char.IsNumber(CurrentChar))
                {
                    number += int.Parse(CurrentChar.ToString()) * (long)Math.Pow(10, pos);
                    if (number > int.MaxValue)
                    {
                        fileName = fileName + "_";
                        pos = 0;
                        number = 1;
                        break;
                    }
                    pos++;
                }
                if (number == 0) number = 1;
                this.fileNameWithoutNumber = fileName.Substring(0, Position + 1);
            }

            void CreateNewFileName()
            {
                while (this.Exists())
                {
                    number++;
                    if (number > int.MaxValue)
                    {
                        fileNameWithoutNumber = fileName + "_";
                        number = 1;
                        break;
                    }
                }
            }

            bool Exists()
            {
                if (this.isDirectory)
                {
                    return Directory.Exists(this.Path);
                }
                else
                {
                    return File.Exists(this.Path);
                }
            }


            int Position
            {
                get { return this.fileName.Length - (pos + 1); }
            }

            char CurrentChar
            {
                get { return this.fileName[Position]; }
            }

            public string Path
            {
                get
                {
                    return System.IO.Path.Combine(this.directory,
                        this.fileNameWithoutNumber + this.NumberString + this.extension);
                }
            }

            string NumberString
            {
                get 
                {
                    if (pos == 0 && number == 0)
                        return string.Empty;
                    return this.number.ToString(new string('0', pos)); 
                }
            }
        }
    }

    public class UtilitiesTest
    {
        public void GetUniqueFileNameTest()
        {
            DoTest(@"C:\temp\one\two\aNiceFile.ext");
            DoTest(@"C:\temp\one\two\theFile.txt");
            DoTest(@"C:\temp\one\two\anotherFile01234.txt");
            DoTest(@"C:\temp\one\two\anotherFile00001.txt");
            DoTest(@"C:\temp\one\two\bigNumber91830810938012981031830219383021983092180298210.txt");

            DoTestDir(@"C:\temp\one\two\");
            DoTestDir(@"C:\temp\one\two");
        }

        private void DoTestDir(string path)
        {
            Console.WriteLine("{0} -> {1}", path, Utilities.GetUniqueFolderName(path));
        }

        public void DoTest(string path)
        {
            Console.WriteLine("{0} -> {1}", path, Utilities.GetUniqueFileName(path));
        }
    }
}
